package org.dromara.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.DeviceAlarm;
import org.dromara.system.domain.VariableAssociation;
import org.dromara.system.domain.VariableAssociationGroup;
import org.dromara.system.domain.VariableAssociationParam;
import org.dromara.system.domain.bo.ValueDescBo;
import org.dromara.system.domain.bo.VariableAssociationBo;
import org.dromara.system.domain.vo.VariableAssociationValueDescVo;
import org.dromara.system.domain.vo.VariableAssociationVo;
import org.dromara.system.mapper.*;
import org.dromara.system.service.ISensorService;
import org.dromara.system.service.IVariableAssociationService;
import org.dromara.system.utils.CalculatorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 变量Service业务层处理
 *
 * @author Lion Li
 * @date 2024-10-21
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class VariableAssociationServiceImpl implements IVariableAssociationService {

    private final VariableAssociationMapper baseMapper;


    private final VariableAssociationParamMapper paramMapper;

    private final DeviceVariableAssociationMapper deviceVariableAssociationMapper;

    private final DeviceAlarmMapper deviceAlarmMapper;


    /**
     * 查询变量
     *
     * @param id 主键
     * @return 变量
     */
    @Override
    public VariableAssociationVo queryById(Long id) {
        VariableAssociationVo variableAssociationVo = baseMapper.selectVoById(id);
        if (variableAssociationVo.getValueDescJson() == null) {
            variableAssociationVo.setValueText(new ArrayList<>());
            variableAssociationVo.setValueDesc("");
        } else {
            List<VariableAssociationValueDescVo> variableAssociationValueDescVo = JsonUtils.parseArray(variableAssociationVo.getValueDescJson(), VariableAssociationValueDescVo.class);
            variableAssociationVo.setValueText(variableAssociationValueDescVo);
            variableAssociationVo.setValueDesc(getTextByValue(variableAssociationValueDescVo, variableAssociationVo.getValue()));
        }
        return variableAssociationVo;
    }

    public String getTextByValue(List<VariableAssociationValueDescVo> valueDescList, BigDecimal value) {
        for (VariableAssociationValueDescVo vo : valueDescList) {
            if (vo.getValue().compareTo(value) == 0) {
                return vo.getText();
            }
        }
        return "";
    }


    /**
     * 分页查询变量列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 变量分页列表
     */
    @Override
    public TableDataInfo<VariableAssociationVo> queryPageList(VariableAssociationBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<VariableAssociation> lqw = buildQueryWrapper(bo);
        Page<VariableAssociationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        if (result.getRecords().isEmpty()) return TableDataInfo.build(result);
        List<Long> groupIds = result.getRecords().stream()
            .map(VariableAssociationVo::getGroupId)
            .distinct()
            .collect(Collectors.toList());

        // 批量查询组名并缓存
        List<VariableAssociationGroup> groupNameList = baseMapper.getVGroupNamesByIds(groupIds);
        // 构建组名映射
        Map<Long, String> groupNameMap = groupNameList.stream()
            .collect(Collectors.toMap(VariableAssociationGroup::getId, VariableAssociationGroup::getGroupName));
        // 设置组名
        for (VariableAssociationVo record : result.getRecords()) {
            record.setGroupName(groupNameMap.getOrDefault(record.getGroupId(), "未知组"));
            if (record.getValueDescJson() == null) {
                record.setValueText(new ArrayList<>());
                record.setValueDesc("");
            } else {
                List<VariableAssociationValueDescVo> variableAssociationValueDescVo = JsonUtils.parseArray(record.getValueDescJson(), VariableAssociationValueDescVo.class);
                record.setValueText(variableAssociationValueDescVo);
                record.setValueDesc(getTextByValue(variableAssociationValueDescVo, record.getValue()));
            }
            record.setTunnelName(getTunnelName(record.getSource()));
        }
        return TableDataInfo.build(result);
    }

    private String getTunnelName(int source) {
        // 创建一个 Map 来存储 tunnelId 和 tunnelName 的对应关系
        long tunnelId;
        Map<Long, String> tunnelNameMap = new HashMap<>();
        tunnelNameMap.put(1L, "应天大街隧道");
        tunnelNameMap.put(2L, "定淮门隧道");
        tunnelNameMap.put(3L, "江心洲大桥");
        if (source==1 || source==2|| source==3){
             tunnelId =2;
        } else if (source==4||source==5) {
            tunnelId =1;
        }else {
            tunnelId =3;
        }
        return tunnelNameMap.getOrDefault(tunnelId, "暂无");
    }


    /**
     * 查询符合条件的变量列表
     *
     * @param bo 查询条件
     * @return 变量列表
     */
    @Override
    public List<VariableAssociationVo> queryList(VariableAssociationBo bo) {
        LambdaQueryWrapper<VariableAssociation> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<VariableAssociation> buildQueryWrapper(VariableAssociationBo bo) {
        LambdaQueryWrapper<VariableAssociation> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getCode()), VariableAssociation::getCode, bo.getCode());
        lqw.like(StringUtils.isNotBlank(bo.getName()), VariableAssociation::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getAlias()), VariableAssociation::getAlias, bo.getAlias());
        lqw.eq(bo.getGroupId() != null, VariableAssociation::getGroupId, bo.getGroupId());
        lqw.eq(bo.getValue() != null, VariableAssociation::getValue, bo.getValue());
        lqw.eq(bo.getVariableType() != null, VariableAssociation::getVariableType, bo.getVariableType());
        lqw.eq(bo.getIdentifier() != null, VariableAssociation::getIdentifier, bo.getIdentifier());
        lqw.eq(bo.getMultiple() != null, VariableAssociation::getMultiple, bo.getMultiple());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), VariableAssociation::getDescription, bo.getDescription());
        lqw.eq(bo.getSortNum() != null, VariableAssociation::getSortNum, bo.getSortNum());
        return lqw;
    }

    /**
     * 新增变量
     *
     * @param bo 变量
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(VariableAssociationBo bo) {
        VariableAssociation add = MapstructUtils.convert(bo, VariableAssociation.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改变量
     *
     * @param bo 变量
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(VariableAssociationBo bo) {
        VariableAssociation update = MapstructUtils.convert(bo, VariableAssociation.class);
        Long deviceId = getDeviceId(bo.getId());
        DeviceAlarm deviceAlarm = deviceAlarmMapper.selectOne(new LambdaQueryWrapper<DeviceAlarm>().eq(DeviceAlarm::getDeviceId, deviceId).eq(DeviceAlarm::getVariableId, bo.getId()));
        if (deviceAlarm != null) {
            deviceAlarmMapper.updateVariableStatusById(deviceAlarm.getVariableId());
            deviceAlarm.setStatus(1L);
            deviceAlarm.setFinishTime(new Date());
            deviceAlarm.setUpdateTime(new Date());
            deviceAlarm.setUpdateBy(LoginHelper.getUserId());
            deviceAlarmMapper.updateById(deviceAlarm);
        }
        return baseMapper.updateById(update) > 0;

    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(VariableAssociation entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除变量信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public int updateVariableAssociationGroup(Long groupId, Collection<Long> ids) {
        int bs = baseMapper.updateVariableAssociationGroupZero(groupId);
        int rs = baseMapper.updateVariableAssociation(groupId, ids);
        return bs + rs;
    }

    @Override
    public int updateVariableAssociationName(Long id, String name) {
        return baseMapper.updateVariableAssociationName(id, name);
    }

    @Override
    public List<VariableAssociation> getVariableAssociationByIdAndSource(int type) {
        return baseMapper.selectList(new LambdaQueryWrapper<VariableAssociation>().eq(VariableAssociation::getSource, type));
    }


    /**
     * modbus 设备采集数据
     *
     * @param id
     * @param value
     */
    @Override
    public void updateSensorValue(Long id, Number value) {
        try {
            // 1. 更新变量关联表的值
            updateVariableAssociationValue(id, value);
            // 2. 计算实际值
            VariableAssociation association = getVariableAssociationById(id);
            double actualValue = calculateActualValue(association, value);
            // 3. 获取设备ID，更新设备状态
            Long deviceId = getDeviceId(id);
            if (deviceId == null) return;
            // 4. 检查阈值并触发报警，同时更新设备状态
            checkAndInsertAlarm(id, deviceId, actualValue, association);
        } catch (Exception e) {
            log.error("Error updating sensor value for id: {}", id, e);
        }
    }

    /**
     * 更新变量关联表的值
     */
    private void updateVariableAssociationValue(Long id, Number value) {
        baseMapper.updateVariableAssociationValue(id, value.toString());
    }

    /**
     * 获取变量关联对象
     */
    private VariableAssociation getVariableAssociationById(Long id) {
        return baseMapper.selectOne(new LambdaQueryWrapper<VariableAssociation>()
            .eq(VariableAssociation::getId, id));
    }


    /**
     * 计算实际值
     */
    private double calculateActualValue(VariableAssociation association, Number value) {
        return CalculatorUtils.calculateActualValue(
            association.getIdentifier(),
            association.getMultiple(),
            value.doubleValue()
        );
    }

    /**
     * 检查阈值并触发报警，同时更新设备状态
     */
    private void checkAndInsertAlarm(Long id, Long deviceId, double actualValue, VariableAssociation association) {
        // 查询最近的阈值参数
        VariableAssociationParam param = paramMapper.findClosestThreshold(id, actualValue);

        if (param != null) {
            // 更新变量关联状态为 2（报警状态）
            baseMapper.updateVariableAssociationStatus(association.getId(), 2);

            // 判断是否存在相同等级的未处理报警
            if (isNewAlarm(deviceId, id, Math.toIntExact(param.getLevel()))) {
                // 插入报警日志
                insertAlarmLog(deviceId, id, actualValue, param, association.getName());
                // 将设备状态更新为 2（报警状态）
                baseMapper.updateDeviceStatus(deviceId, 2);
                log.info("Device ID: {} updated to status 2 (Alarm)", deviceId);
            }
        } else {
            // 未触发报警，设备状态恢复为 1（正常状态）
            baseMapper.updateDeviceStatus(deviceId, 1);
            log.info("Device ID: {} updated to status 1 (Normal)", deviceId);
        }
    }

    /**
     * 判断是否为新的报警
     */
    private boolean isNewAlarm(Long deviceId, Long variableId, int level) {
        return deviceAlarmMapper.selectCount(new LambdaQueryWrapper<DeviceAlarm>()
            .eq(DeviceAlarm::getDeviceId, deviceId)
            .eq(DeviceAlarm::getVariableId, variableId)
            .eq(DeviceAlarm::getStatus, 0)
            .eq(DeviceAlarm::getLevel, level)) == 0;
    }

    /**
     * 插入报警日志
     */
    private void insertAlarmLog(Long deviceId, Long variableId, double value,
                                VariableAssociationParam param, String variableName) {
        DeviceAlarm log = new DeviceAlarm();
        log.setLevel(param.getLevel());
        log.setAlarmValue(Double.toString(value));
        log.setDeviceId(deviceId);
        log.setVariableId(variableId);
        log.setTunnelId(deviceAlarmMapper.getTunnelNameByDeviceId(deviceId));
        log.setDeviceGroup(deviceAlarmMapper.getDeviceGroupNameByDeviceId(deviceId));
        log.setVariableName(variableName);
        String deviceName = deviceAlarmMapper.getDeviceNameById(deviceId);
        log.setDeviceName(deviceName);
        log.setContent(String.format("%s 下的传感器 %s 的数值为 %.2f 在 %s 发生了等级为 %d 报警",
            deviceName, variableName, value, LocalDate.now(), param.getLevel()));
        deviceAlarmMapper.insert(log);
    }

//    public void updateSensorValue(Long id, Number value) {
//        try {
//            double actualValue;
//            baseMapper.updateVariableAssociationValue(id, value.toString());
//            // 根据规则求实际值
//            VariableAssociation association = baseMapper.selectOne(new LambdaQueryWrapper<VariableAssociation>().eq(VariableAssociation::getId, id).eq(VariableAssociation::getSource, 1));
//            actualValue = CalculatorUtils.calculateActualValue(association.getIdentifier(), association.getMultiple(), value.doubleValue());
//
//            // 获取设备ID和变量名称
//            Long deviceId = getDeviceId(id);
//            String variableName = association.getName();
//            if (deviceId == null) return;
//            //更新设备状态
//            baseMapper.updateVariableAssociationStatus(association.getId(), 1);
//            baseMapper.updateDeviceStatus(deviceId, 1);
//            // 查询value靠近的最近的参数列表1条
//            VariableAssociationParam variableAssociationParams = paramMapper.findClosestThreshold(id,value.doubleValue());
//            if (variableAssociationParams != null){
//                baseMapper.updateVariableAssociationStatus(association.getId(), 2);
//                Long count = deviceAlarmMapper.selectCount(new LambdaQueryWrapper<DeviceAlarm>()
//                        .eq(DeviceAlarm::getDeviceId, deviceId)
//                        .eq(DeviceAlarm::getVariableId, id)
//                        .eq(DeviceAlarm::getStatus, 0)
//                        .eq(DeviceAlarm::getLevel, variableAssociationParams.getLevel()));
//                if (count == 0) {
//                    // 插入报警日志
//                    DeviceAlarm log = new DeviceAlarm();
//                    log.setLevel(variableAssociationParams.getLevel());
//                    log.setAlarmValue(Double.toString(actualValue));
//                    log.setDeviceId(deviceId);
//                    log.setVariableId(id);
//                    log.setTunnelId(deviceAlarmMapper.getTunnelNameByDeviceId(deviceId));
//                    log.setDeviceGroup(deviceAlarmMapper.getDeviceGroupNameByDeviceId(deviceId));
//                    log.setVariableName(variableName);
//                    String deviceName = deviceAlarmMapper.getDeviceNameById(deviceId);
//                    log.setDeviceName(deviceName);
//                    log.setContent(String.format("%s 下的传感器 %s 的数值为 %.2f 在 %s 发生了等级为 %d 报警",
//                            deviceName, variableName, actualValue, LocalDate.now(), variableAssociationParams.getLevel()));
//                    deviceAlarmMapper.insert(log);
//                }
////            }else {
////                List<VariableAssociationParam> params = paramMapper.selectByVariableIdAndThresholdsNotEqual(id);
////                if (params != null && !params.isEmpty()) {
////                    for (VariableAssociationParam param : params) {
////                        //让变量更新status=2 便是该变量为报警设备
////                        baseMapper.updateVariableAssociationStatus(association.getId(), 2);
////                        // 判断是否在报警区间内
////                        double upThreshold = Double.parseDouble(param.getUpThreshold());
////                        log.info("上线阈值:{}", upThreshold);
////                        double downThreshold = Double.parseDouble(param.getDownThreshold());
////                        log.info("下线阈值:{}", upThreshold);
////                        Long count = deviceAlarmMapper.selectCount(new LambdaQueryWrapper<DeviceAlarm>()
////                                .eq(DeviceAlarm::getDeviceId, deviceId)
////                                .eq(DeviceAlarm::getVariableId, id)
////                                .eq(DeviceAlarm::getStatus, 0)
////                                .eq(DeviceAlarm::getLevel, variableAssociationParams.getLevel()));
////                        if (count == 0) {
////                            // 插入报警日志
////                            DeviceAlarm log = new DeviceAlarm();
////                            log.setLevel(param.getLevel());
////                            log.setAlarmValue(Double.toString(actualValue));
////                            log.setDeviceId(deviceId);
////                            log.setVariableId(id);
////                            log.setTunnelId(deviceAlarmMapper.getTunnelNameByDeviceId(deviceId));
////                            log.setDeviceGroup(deviceAlarmMapper.getDeviceGroupNameByDeviceId(deviceId));
////                            log.setVariableName(variableName);
////                            String deviceName = deviceAlarmMapper.getDeviceNameById(deviceId);
////                            log.setDeviceName(deviceName);
////                            log.setContent(String.format("%s 下的传感器 %s 的数值为 %.2f 在 %s 发生了等级为 %d 报警",
////                                    deviceName, variableName, actualValue, LocalDate.now(), param.getLevel()));
////                            deviceAlarmMapper.insert(log);
////                        }
////                    }
////
////                }
//            }
//
//        } catch (Exception e) {
//            // 异常处理
//            e.printStackTrace();
//            // 可以添加更多的日志记录或异常处理逻辑
//        }
//    }

    /**
     * 水浸设备
     *
     * @param variableAssociations
     */

    @Override
    public void insertOrUpdateByBo(List<VariableAssociation> variableAssociations) {
        for (VariableAssociation variableAssociation : variableAssociations) {
            String code = variableAssociation.getCode();
            VariableAssociation existingAssociation = baseMapper.findByCode(code);
            if (existingAssociation != null) {
                // 更新现有记录
                existingAssociation.setStatus(variableAssociation.getStatus());
                existingAssociation.setName(variableAssociation.getName());
                existingAssociation.setAlias(variableAssociation.getAlias());
                existingAssociation.setCreateBy(variableAssociation.getCreateBy());
                existingAssociation.setSource(7);
                LambdaUpdateWrapper<VariableAssociation> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(VariableAssociation::getId, existingAssociation.getId());
                baseMapper.updateVariableAssociationValue(existingAssociation.getId(), String.valueOf(existingAssociation.getValue()));
                baseMapper.update(existingAssociation, updateWrapper);
            } else {
                // 插入新记录
                variableAssociation.setSource(7);
                baseMapper.insert(variableAssociation);
                baseMapper.updateVariableAssociationValue(variableAssociation.getId(), String.valueOf(variableAssociation.getValue()));

            }
            // 插入报警
            insertDeviceAlarm(variableAssociation);
        }
    }

    @Override
    public int setVariableAssociationValueDesc(Long id, ValueDescBo bo) {
        VariableAssociation variableAssociation = baseMapper.selectById(id);
        variableAssociation.setValueDescJson(bo.getValueText());
        return baseMapper.updateById(variableAssociation);
    }

    @Override
    public void updatePointSensorValue(Long id, BigDecimal value) {
        baseMapper.updateVariableAssociationValue(id, value.toString());
    }

    @Override
    public void updateDeviceStatus(long sensorId) {
        baseMapper.updateDeviceStatusBySensorId(sensorId);
    }

    private void insertDeviceAlarm(VariableAssociation variableAssociation) {
        DeviceAlarm log = new DeviceAlarm();
        log.setLevel(1L);
        log.setAlarmValue(String.valueOf(variableAssociation.getValue()));
        Long deviceId = getDeviceId(variableAssociation.getId());
        if (deviceId == null) return;
        Long id = variableAssociation.getId();
        String variableName = variableAssociation.getName();
        log.setVariableName(variableName);
        String deviceName = deviceAlarmMapper.getDeviceNameById(deviceId);
        log.setDeviceName(deviceName);

        // 检查是否存在相同的报警记录
        Long count = deviceAlarmMapper.selectCount(new LambdaQueryWrapper<DeviceAlarm>()
            .eq(DeviceAlarm::getDeviceId, deviceId)
            .eq(DeviceAlarm::getVariableId, id)
            .eq(DeviceAlarm::getLevel, 1L)
            .eq(DeviceAlarm::getAlarmValue, log.getAlarmValue()));

        if (count == 0) {
            // 生成日志内容
            String content = String.format("设备名为 %s 下的传感器名称为 %s 的数值为 %s 在 %s 发生了等级为 %d 报警",
                deviceName, variableName, variableAssociation.getValue(), LocalDateTime.now(), 1);
            log.setContent(content);
            log.setDeviceId(deviceId);
            log.setVariableId(id);
            deviceAlarmMapper.insert(log);
        }
    }


    private Long getDeviceId(Long id) {
        return deviceVariableAssociationMapper.selectByVariableId(id);
    }

}
